package edu.csu.smartpark.handler;

import edu.csu.smartpark.model.common.BusinessException;
import edu.csu.smartpark.model.common.MsgEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.xml.bind.ValidationException;

@Slf4j
@ControllerAdvice
@ResponseBody
public class ControllerExceptionHandler {
    @ExceptionHandler(BusinessException.class)
    public MsgEntity businessExceptionHandle(BusinessException ex) {
        log.error("[Smart Park Server] Business execution failed - "+ex.getClass().getName() + ":" + ex.getMessage());
        return new MsgEntity("fail", ex.getCode(),"[Smart Park Server] Business execution failed: " + ex.getMessage());
    }

    @ExceptionHandler(UnauthorizedException.class)
    //@ResponseStatus(value= HttpStatus.FORBIDDEN)
    public MsgEntity unauthorizedExceptionHandle(UnauthorizedException ex) {
        return new MsgEntity("error",MsgEntity.UNAUTHORIZED,"[Smart Park Server] Unauthorized: " + ex.getMessage());
    }

    @ExceptionHandler(UnauthenticatedException.class)
    //@ResponseStatus(value= HttpStatus.FORBIDDEN)
    public MsgEntity unAuthenticationExceptionHandle(UnauthenticatedException ex) {
        return new MsgEntity("error",MsgEntity.UNAUTHORIZED,"[Smart Park Server] UnAuthentication: " + ex.getMessage());
    }

    @ExceptionHandler(AuthenticationException.class)
    //@ResponseStatus(value = HttpStatus.FORBIDDEN)
    public MsgEntity authenticationExceptionHandle(AuthenticationException ex) {
        return new MsgEntity("error",MsgEntity.UNAUTHORIZED,"[Smart Park Server] UnAuthentication: " + ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    @ResponseStatus(value= HttpStatus.INTERNAL_SERVER_ERROR)
    public MsgEntity systemUnexpectedExceptionHandle(Exception ex) {
        log.error("[Smart Park Server] SYSTEM FAIL - "+ex.getClass().getName(), ex.getMessage());
        ex.printStackTrace();
        return new MsgEntity("error",MsgEntity.INTERNAL_SERVER_ERROR,"[Smart Park Server] "+ex.getClass().getName()+": "+ex.getMessage());
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public MsgEntity methodArgumentNotValidExceptionHandle(MethodArgumentNotValidException ex){
        log.error("[Smart Park Server] Argument validation error - " + ex.getClass().getName() + ":" + ex.getMessage());
        return new MsgEntity("fail", BusinessException.PARAMETERERROR, ex.getBindingResult().getFieldError().getDefaultMessage());
    }

    @ExceptionHandler(ValidationException.class)
    public MsgEntity validationExceptionHandle(ValidationException ex){
        log.error("[Smart Park Server] Argument validation fail - " + ex.getClass().getName() + ":" + ex.getMessage());
        return new MsgEntity("fail", BusinessException.PARAMETERERROR, ex.getMessage());
    }
}
